#ifndef SCENEELEMENTS_HEADER_VIZMF_PROJECT
#define SCENEELEMENTS_HEADER_VIZMF_PROJECT

#include "src/core/scene/sceneelement.h"
#include <vector>

/*
  VizMF SceneElements class

  Defines a set of geometric primitives a scene which are independent of its contents
*/
// for now it's a stub necessary to define the interface to external world
class SceneElements {
protected:
  typedef std::vector<Scene3DElement*> D3_prim_vec_type;
  typedef std::vector<Scene2DElement*> D2_prim_vec_type;

  // this template is used in destructor
  template<class T>
  struct del : public std::unary_function<T, void>
  {
    del() {}
    void operator() (T* x) { delete x;}
  };


public:
  typedef float float_type;
  typedef D3_prim_vec_type::size_type size_type;

  SceneElements(){}
  virtual ~SceneElements(){}

  // 3D primitive creators go below
  void createSphere(const Vector3& center, const float_type& radius, const Material& mat){
    d3_prim_vec_.push_back(new Sphere(center, radius, mat));
  }
  void createCylinder(const Vector3& from, const Vector3& to, const float_type& radFrom, const float_type& radTo, const Material& mat){
    d3_prim_vec_.push_back(new Cylinder(from, to, radFrom, radTo, mat));
  }
  // could be overloaded if needed
  void createParallelepiped(const Vector3& vertex, const Vector3& a, const Vector3& b, const Vector3& c, const Material& mat){
    d3_prim_vec_.push_back(new Parallelepiped(vertex, a, b, c, mat));
  }

  // 2D primitive creators go below
  void createPoint(const Vector3& center, const Material& mat){
    d3_prim_vec_.push_back(new Point(center, mat));
  }
  void createLine(const Vector3& vec1, const Vector3& vec2, const Material& mat){
    d3_prim_vec_.push_back(new Line(vec1, vec2, mat));
  }
  void createCircle(const Vector3& center, const float_type& radius, const Material& mat){
    d2_prim_vec_.push_back(new Circle(center, radius, mat));
  }
  void createCone(const Vector3& from, const Vector3& to, const float_type& radius, const Material& mat)
  {
    d3_prim_vec_.push_back(new Cone(from, to, radius, mat));
  }

//  void createEllipse(/**/){ // watch out, it's a stub!
//    d2_prim_vec_.push_back(new Ellipse(/**/));
//  }
//  void createRectangle(const Vector3& vertex, const Vector3& dx, const Vector3& dy, const Material& mat){
//    d2_prim_vec_.push_back(new Rectangle(vertex, dx, dy, mat));
//  }

// other interface functions
  void clear(){
    std::for_each(d3_prim_vec_.begin(), d3_prim_vec_.end(), del<Scene3DElement>());
    std::for_each(d2_prim_vec_.begin(), d2_prim_vec_.end(), del<Scene2DElement>());
    d3_prim_vec_.clear();
    d2_prim_vec_.clear();
  }

  size_type number3DElements() const {return d3_prim_vec_.size();}
  size_type number2DElements() const {return d2_prim_vec_.size();}

  // rather useless in the current form but nevertheless...
  const Scene3DElement& get3DElem(size_type index) const {return *d3_prim_vec_[index];}
  const Scene2DElement& get2DElem(size_type index) const {return *d2_prim_vec_[index];}

  /*
  // more interested and useful would be
    iterator_type beginSpheres();
    iterator_type endSpheres();
    iterator_type beginCylinders();
    iterator_type endCylinders();
    // ..., etc.
  */

protected:
  D3_prim_vec_type d3_prim_vec_;
  D2_prim_vec_type d2_prim_vec_;

  // the below vectors index primitive types in general 3d_prim_vec_ and 2d_prim_vec_ vectors
  std::vector<bool> spheres_;
  std::vector<bool> cyls_;
  std::vector<bool> paralls_;
  // ..., etc.

/* A viable alternative could be an explicict enumeration:
     // for 3D
     std::vector<Sphere*> sphere_vec_;
     std::vector<Cylinder*> cyl_vec_;
     std::vector<Parallelepiped*> parpd_vec_;
     std::vector<Scene3DElements*> 3d_gen_vec_; // general 3D element
     // for 2D
     std::vector<Point*> point_vec_;
     std::vector<Line*> line_vec_;
     std::vector<Circle*> circle_vec_;
     std::vector<Ellipse*> ell_vec_;
     std::vector<Rectangle*> rect_vec_;
     std::vector<Scene3DElements*> 2d_gen_vec_; // general 3D element
*/
};

/*
  todo:
    1) Should primitive properties (Material, shininess, transparency, etc.) be stored directly in primitives or separately
    2) Which kinds of properties to make common, i.e. stored in SceneElements, independent from further drawer (be it OpenGL widget or other)
*/

#endif // SCENEELEMENTS_HEADER_VIZMF_PROJECT
